package neptune.manager.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.trilead.ssh2.Connection;
import com.trilead.ssh2.Session;
import com.trilead.ssh2.StreamGobbler;

/**
 * @author Luigi Lorenzo Arpino [luigiarpino@yahoo.it]
 * 
 */
public class SSHConnectionHandler {

	private BufferedReader stdOut;
	private BufferedReader stdErr;
	private Connection connection;
	private Session session;
	
	// Timeout in millisecond
	private static int CONNECTION_TIMEOUT=12000; 

	/**
	 * Crea un gestore per una singola connessione ssh2
	 * 
	 * @param sshClient
	 */
	public SSHConnectionHandler(Connection conn) {
		this.connection = conn;
		this.session = null;
	}

	/**
	 * Invia un comando sulla connessione ssh2. Il risultato del comando, in
	 * termini di risposta della connessione ssh, viene riportato nello stdOut,
	 * che puo' essere letto dopo aver eseguito il comando.
	 * 
	 * Qualora il comando eseguito non dovesse terminare con valore di ritorno
	 * 0, viene lanciata una eccezione.
	 * 
	 * @param command
	 * @throws SSHCommandException
	 * @throws
	 */
	public void sendCommand(String command) throws SSHCommandException {
		DebugLog.printDetailedLog("Executing command: " + command,
				SSHConnectionHandler.class.getSimpleName());
		try {
			if (this.session != null)
				this.session.close();
			session = this.connection.openSession();
			session.execCommand(command);
			InputStream stdout = new StreamGobbler(session.getStdout());
			this.stdOut = new BufferedReader(new InputStreamReader(stdout));
		} catch (IOException e) {
			throw new SSHCommandException(e.getMessage());
		}
	}

	/**
	 * Invia un comando sulla connessione ssh2. Il risultasto del comando, in
	 * termini di risposta della connessione ssh, viene riportato nello stdOut,
	 * che puo' essere letto dopo aver eseguito il comando.
	 * 
	 * Il valore di ritorno con cui termina il comando viene restituito dal
	 * metodo. Questa metodo puo' essere usato per eseguire quei comandi la cui
	 * mancata terminazione con 0 non e' considerata un'eccezione.
	 * 
	 * @param command
	 * @throws IOException
	 * @throws SSHCommandException
	 */
	public int sendCommandNoErrorControl(String command) {
		DebugLog.printDetailedLog(
				"Executing command (no err ctrl): " + command,
				SSHConnectionHandler.class.getSimpleName());
		try {
			if (this.session != null)
				this.session.close();
			session = this.connection.openSession();
			session.execCommand(command);
			InputStream stdout = new StreamGobbler(session.getStdout());
			this.stdOut = new BufferedReader(new InputStreamReader(stdout));
			InputStream stdErr = new StreamGobbler(session.getStderr());
			this.stdErr = new BufferedReader(new InputStreamReader(stdErr));
			int status ;
			try
			{
				status = session.getExitStatus();
			}
			catch (Exception e)
			{
				status = 1;
				System.out.println("ERROR: executing comand "+command );
			}
			return status;
		} catch (IOException e) {
			return 1;
		}
	}

	/**
	 * Chiude la connessione ssh2 legata a questo gestore
	 */
	public void dispose() {
		if (this.session != null)
			this.session.close();

		this.connection.close();

		DebugLog.printDetailedLog("Disconnected", SSHConnectionHandler.class
				.getSimpleName());
	}

	/**
	 * @return the stdOut
	 */
	public BufferedReader getStdOut() {
		return stdOut;
	}

	/**
	 * 
	 * @return
	 */
	public BufferedReader getStdErr() {
		return this.stdErr;
	}

	public static SSHConnectionHandler createSSHConnectionHandler(
			String ipAddress, int port, String username, String password)
			throws IOException {

		DebugLog.printDetailedLog("Try to connect to " + ipAddress + ":" + port
				+ "...", SSHConnectionHandler.class.getSimpleName());
		// creo la connessione
		Connection conn = new Connection(ipAddress);
		// faccio la connessione
		conn.connect(null, CONNECTION_TIMEOUT, CONNECTION_TIMEOUT);
		// Autenticazione
		boolean isAuthenticated = conn.authenticateWithPassword(username,
				password);
		// Controllo se il tipo di autenticazione è corretto
		if (isAuthenticated == false)
			throw new IOException("Authentication failed.");
		// genero il SSHConnectionHandler
		DebugLog.printDetailedLog("... connected to " + ipAddress + ":" + port,
				SSHConnectionHandler.class.getSimpleName());
		return new SSHConnectionHandler(conn);
	}
	
	public static void main(String[] args) throws IOException
	{
		SSHConnectionHandler handler = SSHConnectionHandler.createSSHConnectionHandler("192.168.122.51", 22, "root", "antoxps");
		handler.sendCommandNoErrorControl("tc qdisc del dev eth0 root");
	}

}
